//
//  ZBNetworkManager.m
//  ZBDay
//
//  Created by xzb on 2018/2/5.
//  Copyright © 2018年 xzb. All rights reserved.
//

#import "ZBNetworkManager.h"
#import "ZBNetworkManager+Reachability.h"
#import "ZBJsonResponseSerializer.h"

@interface ZBNetworkManager ()

@property (nonatomic, strong) UIView *noConnectionTip;
@property (nonatomic, assign) BOOL manualRemovedNoConnectionTip;
@property (nonatomic, strong, readwrite) AFHTTPSessionManager *afSessionManagerForDataTransmission;

- (void)showNoConnectionTip;
@end

static NSArray<Class> *URLProtocols;

@implementation ZBNetworkManager

+ (instancetype)instance
{
    static dispatch_once_t oncePredicate;
    static id instance;
    dispatch_once(&oncePredicate, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

#pragma mark - AFHTTPSessionManager
+ (AFHTTPSessionManager *)AFHTTPSessionManager
{
    static AFHTTPSessionManager *manager;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        manager = [[AFHTTPSessionManager alloc] init];
        manager.requestSerializer.timeoutInterval = 15;
        //https ssl 验证。
        //manager.securityPolicy = [ZBNetworkManager customSecurityPolicy];
        ZBJsonResponseSerializer *responseSerializer = [ZBJsonResponseSerializer serializer];
        manager.responseSerializer = responseSerializer;
        [ZBNetworkManager rechabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            if (status > 0) {
                [[ZBNetworkManager instance] hideNoConnectionTip];
            } else {
                [[ZBNetworkManager instance] showNoConnectionTip];
            }
        }];
    });
    
    return manager;
}

+ (NSURLSessionTask *)sendRequestType:(NSString *)type urlStr:(NSString *)urlStr params:(NSDictionary *)params headers:(NSDictionary *)headers success:(onZBCompletionBlock)success failure:(onZBErrorBlock)failure
{
    AFHTTPRequestSerializer *requestSerializer = [ZBNetworkManager AFHTTPSessionManager].requestSerializer;
    //Cookie
    [requestSerializer setValue:@"" forHTTPHeaderField:@"Cookie"];
    
    void (^ successBlock)(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject)
    = ^(NSURLSessionDataTask *_Nonnull task, ZBResponseModel *_Nullable responseModel) {
        if (success) {
            success(responseModel);
        }
    };
    void (^ failureBlock)(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error)
    = ^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error) {
        if (failure) {
            failure(error);
        }
    };
    NSString *reqType = [type uppercaseString];
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [requestSerializer requestWithMethod:reqType URLString:urlStr parameters:params error:&serializationError];
    
    if (!request || !request.URL) {
        dispatch_async([ZBNetworkManager AFHTTPSessionManager].completionQueue ? : dispatch_get_main_queue(), ^{
            failureBlock(nil, [NSError ZB_errorWithCode:1 errorMessage:[NSString stringWithFormat:@"无效的 URL: %@", urlStr]]);
        });
        return nil;
    }
    if (serializationError) {
        dispatch_async([ZBNetworkManager AFHTTPSessionManager].completionQueue ? : dispatch_get_main_queue(), ^{
            failureBlock(nil, serializationError);
        });
        return nil;
    }
    for (NSString *key in headers) {
        [request setValue:headers[key] forHTTPHeaderField:key];
    }
    __block NSURLSessionDataTask *dataTask = nil;
    
    dataTask = [[ZBNetworkManager AFHTTPSessionManager] dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse *__unused response, id responseObject, NSError *error) {
        if (error) {
            failureBlock(dataTask, error);
        } else {
            successBlock(dataTask, responseObject);
        }
    }];
    
    [ZBNetworkManager instance].manualRemovedNoConnectionTip = NO;
    [dataTask resume];
    
    return nil;
}

+ (NSURLSessionUploadTask *)uploadFileWithUrl:(NSString *)url
                                       params:(NSDictionary *)dict
                                         data:(NSData *)data
                                CompleteBlock:(onZBCompletionBlock)onComplete
                                 ZBErrorBlock:(onZBErrorBlock)onError
                                ProgressBlock:(onProgressBlock)progressBlock
{
    return [self uploadFileWithUrl:url
                            params:dict
                              data:data
                              name:@"file"
                          fileName:@"file"
                          mimeType:@"application/octet-stream"
                        onComplete:onComplete
                           onError:onError
                        onProgress:progressBlock];
}

+ (NSURLSessionUploadTask *)uploadFileWithUrl:(NSString *)url
                                       params:(NSDictionary *)dict
                                         data:(NSData *)data
                                         name:(NSString *)name
                                     fileName:(NSString *)fileName
                                     mimeType:(NSString *)mimeType
                                   onComplete:(onZBCompletionBlock)onComplete
                                      onError:(onZBErrorBlock)onError
                                   onProgress:(onProgressBlock)onProgress
{
    NSString *urlString = url;
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST"  URLString:urlString parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileData:data name:name fileName:fileName mimeType:mimeType];
    } error:nil];
    NSURLSessionUploadTask *uploadTask = [[ZBNetworkManager AFHTTPSessionManager] uploadTaskWithStreamedRequest:request progress:^(NSProgress *_Nonnull uploadProgress) {
        if (onProgress) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // Update the progress view
                onProgress(uploadProgress);
            });
        }
    }  completionHandler:^(NSURLResponse *_Nonnull response, ZBResponseModel *_Nullable responseModel, NSError *_Nullable error) {
        if (onComplete && responseModel) {
            onComplete(responseModel);
        } else if (onError && error) {
            onError(error);
        }
    }];
    [uploadTask resume];
    return uploadTask;
}

- (NSURLSessionDownloadTask *)downloadFileWithUrl:(NSString *)url
                                          dirPath:(NSString *)dirPath
                                         filename:(NSString *)filename
                                       onComplete:(onDownloadRespBlock)onComplete
                                       onProgress:(onProgressBlock)onProgress
{
    NSURL *URL = [NSURL URLWithString:url];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLSessionDownloadTask *downloadTask = [self.afSessionManagerForDataTransmission downloadTaskWithRequest:request progress:^(NSProgress *_Nonnull downloadProgress) {
        if (onProgress) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // Update the progress view
                onProgress(downloadProgress);
            });
        }
    } destination:^NSURL *_Nonnull (NSURL *_Nonnull targetPath, NSURLResponse *_Nonnull response) {
        NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:dirPath];
        return [documentsDirectoryURL
                URLByAppendingPathComponent:filename ? : [response suggestedFilename]];
    } completionHandler:^(NSURLResponse *_Nonnull response, NSURL *_Nullable filePath, NSError *_Nullable error) {
        ZBDownLoadRespModel *downModel = [ZBDownLoadRespModel new];
        downModel.response = response;
        downModel.filePath = filePath;
        downModel.error = error;
        onComplete(downModel);
    }];
    [downloadTask resume];
    return downloadTask;
}

#pragma mark - https认证

+ (AFSecurityPolicy *)customSecurityPolicy
{
    //    NSData *certData = nil;
    AFSecurityPolicy *securityPolicy = nil;
    /*
     securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
     // AFSSLPinningModeCertificate 使用证书验证模式
     NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"mhuayinglicaicom" ofType:@"cer"];
     certData = [NSData dataWithContentsOfFile:cerPath];
     securityPolicy.pinnedCertificates = [NSSet setWithObject:certData];
     // allowInvalidCertificates 是否允许无效证书（也就是自建的证书），默认为NO
     // 如果是需要验证自建证书，需要设置为YES
     securityPolicy.allowInvalidCertificates = NO;
     
     //validatesDomainName 是否需要验证域名，默认为YES；
     //假如证书的域名与你请求的域名不一致，需把该项设置为NO；如设成NO的话，即服务器使用其他可信任机构颁发的证书，也可以建立连接，这个非常危险，建议打开。
     //如置为NO，建议自己添加对应域名的校验逻辑。
     securityPolicy.validatesDomainName = NO;
     */
    return securityPolicy;
}

#pragma mark - Tip
- (void)showNoConnectionTip
{
    if (self.manualRemovedNoConnectionTip) {
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if (![[UIApplication sharedApplication].delegate window]) {
            return;
        }
        if (self.noConnectionTip) {
            [self.noConnectionTip.superview bringSubviewToFront:self.noConnectionTip];
            return;
        }
        UIView *shadowWrapper = [[UIView alloc] initWithFrame:CGRectMake(10, -64, [UIScreen mainScreen].bounds.size.width - 20, 64)];
        UIView *tip = [[UIView alloc] initWithFrame:shadowWrapper.bounds];
        [shadowWrapper addSubview:tip];
        shadowWrapper.backgroundColor = [UIColor clearColor];
        UILabel *label = [UILabel new];
        tip.backgroundColor = [UIColor whiteColor];
        tip.layer.cornerRadius = 15;
        tip.clipsToBounds = YES;
        tip.alpha = 0.95;
        shadowWrapper.layer.shadowColor = [UIColor blackColor].CGColor;
        shadowWrapper.layer.shadowOffset = CGSizeMake(0, 7);
        shadowWrapper.layer.shadowRadius = 15;
        shadowWrapper.layer.shadowOpacity = 0.5;
        label.backgroundColor = [UIColor clearColor];
        label.textColor = [UIColor blackColor];
        label.font = [UIFont systemFontOfSize:16];
        label.adjustsFontSizeToFitWidth = YES;
        label.textAlignment = NSTextAlignmentLeft;
        label.text = @"⚠️ 网络请求失败，请检查您的网络设置";
        [label sizeToFit];
        label.frame = CGRectMake(20,
                                 0,
                                 MIN(label.frame.size.width, tip.frame.size.width - 40),
                                 tip.frame.size.height);
        [tip addSubview:label];
        UIButton *btn = [[UIButton alloc] initWithFrame:tip.bounds];
        [tip addSubview:btn];
        [btn addTarget:self
                action:@selector(noConnectionTipTouched)
      forControlEvents:UIControlEventTouchUpInside];
        UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                    action:@selector(manualRemoveNoConnectionTip)];
        swipe.direction = UISwipeGestureRecognizerDirectionUp;
        [btn addGestureRecognizer:swipe];
        [[[UIApplication sharedApplication].delegate window] addSubview:shadowWrapper];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:0.5 animations:^{
                CGRect f = shadowWrapper.frame;
                f.origin = CGPointMake(f.origin.x, 20);
                shadowWrapper.frame = f;
            }];
        });
        self.noConnectionTip = shadowWrapper;
    });
}

- (void)manualRemoveNoConnectionTip
{
    [UIView animateWithDuration:0.15 animations:^{
        CGRect f = self.noConnectionTip.frame;
        [self.noConnectionTip setFrame:CGRectMake(f.origin.x, -f.size.height, f.size.width, f.size.height)];
    } completion:^(BOOL finished) {
        [self.noConnectionTip removeFromSuperview];
        self.noConnectionTip = nil;
        self.manualRemovedNoConnectionTip = YES;
    }];
}

- (void)hideNoConnectionTip
{
    if (!self.noConnectionTip) {
        return;
    }
    [UIView animateWithDuration:0.35 animations:^{
        CGRect f = self.noConnectionTip.frame;
        [self.noConnectionTip setFrame:CGRectMake(f.origin.x, -f.size.height, f.size.width, f.size.height)];
    } completion:^(BOOL finished) {
        [self.noConnectionTip removeFromSuperview];
        self.noConnectionTip = nil;
    }];
}

- (void)noConnectionTipTouched
{
    //无网络处理界面
    [ZBToast showToast:@"请检查网络"];
}

- (AFHTTPSessionManager *)afSessionManagerForDataTransmission
{
    @synchronized (self) {
        if (!_afSessionManagerForDataTransmission) {
            NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
            config.protocolClasses = URLProtocols;
            _afSessionManagerForDataTransmission = [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:config];
            _afSessionManagerForDataTransmission.requestSerializer.timeoutInterval = 15;
            ZBJsonResponseSerializer *responseSerializer = [ZBJsonResponseSerializer serializer];
            _afSessionManagerForDataTransmission.responseSerializer = responseSerializer;
            [_afSessionManagerForDataTransmission.requestSerializer setValue:@"gzip, deflate" forHTTPHeaderField:@"Accept-Encoding"];
        }
        return _afSessionManagerForDataTransmission;
    }
}

@end
@implementation ZBResponseModel
@end
@implementation ZBDownLoadRespModel
@end
